package cn.itcast.web.shiro;

import cn.itcast.domain.system.Module;
import cn.itcast.domain.system.User;
import cn.itcast.service.system.ModuleService;
import cn.itcast.service.system.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.HashSet;
import java.util.List;

public class AuthRealm extends AuthorizingRealm {
    @Autowired
    private UserService userService;
    @Autowired
    private ModuleService moduleService;

    //编写认证逻辑
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {


        //1.查询数据库的用户名
        //1.1 获取用户输入的用户名
        UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
        String email = token.getUsername();
        //1.2 查询用户名
        User user = userService.findByEmail(email);

        //2.判断用户名是否存在，如果不存在，返回null
        if(user==null){
            return null;  //return null底层是抛出UnknownAccountException异常
        }

        //3.返回AuthenticationInfo对象，携带数据库的密码即可
        /**
         * 参数一：principal，存放用户登录信息，subject.getPrincipal()获取
         * 参数二：数据库的密码
         * 参数三：realm的别名，只有在多个用户表的时候才会用，一般不用
         */
        AuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),"");
        return info;
    }

    //编写授权逻辑
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        //1.获取当前登录用户
        Subject subject = SecurityUtils.getSubject();
        User user = (User)subject.getPrincipal();

        //2.根据登录用户id获取拥有的权限（模块）
        HashSet<Module> moduleList = moduleService.findModuleById(user.getId());

        //3.把权限标记存入AuthorizationInfo对象
        //在配置拦截时使用
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        if(moduleList!=null){
            for(Module module:moduleList){

                //把模块的name作为权限标记来存储
                if(module.getName()!=null) {
                    info.addStringPermission(module.getName());
                }
            }
        }

        return info;
    }

}
